#ifndef __POLYTASK_H__
#define __POLYTASK_H__

#include "tbb/combinable.h"
#include "cnc/cnc.h"
#include "cnc/default_tuner.h"

using namespace std;

#include "cnc/debug.h"

// forward declaration
class polyTask_context;

#include "TaskTag.hpp"
#include "Threading.hpp"

// PolyTask core class
template <int TASK_ID, int TASKTAGDIM, int INTERTASKDIM> class polyTask_step {
public:
  mutable tbb::combinable<bool> pinned;
  polyTask_step() : pinned(false) {}

  int64_t execute
  (const TaskTag<TASK_ID, TASKTAGDIM, INTERTASKDIM> &, 
   polyTask_context &) const;
};

// PolyTask tuner class
template <int TASK_ID, int TASKTAGDIM, int INTERTASKDIM> class polyTask_tuner : 
  public CnC::step_tuner<>, public CnC::tag_tuner<>, public CnC::hashmap_tuner {
public:
  polyTask_tuner() {}
  template< class DC >
  void depends(const TaskTag<TASK_ID, TASKTAGDIM, INTERTASKDIM> &, 
               polyTask_context &, DC &) const;
};


// Context for a single polyTask 
class polyTask_context : 
public CnC::context< polyTask_context> {
public:
  polyTask_tuner <0, TASKTAGDIMMACRO, INTERTASKDIMMACRO> m_tuner;
  CnC::item_collection< TaskTag<0, TASKTAGDIMMACRO, INTERTASKDIMMACRO>, 
                        void *, polyTask_tuner<0, TASKTAGDIMMACRO, INTERTASKDIMMACRO> > M;
  CnC::step_collection< polyTask_step<0, TASKTAGDIMMACRO, INTERTASKDIMMACRO>, 
                        polyTask_tuner<0, TASKTAGDIMMACRO, INTERTASKDIMMACRO> 
                        > m_steps;
  CnC::tag_collection< TaskTag<0, TASKTAGDIMMACRO, INTERTASKDIMMACRO> , 
                       polyTask_tuner<0, TASKTAGDIMMACRO, INTERTASKDIMMACRO> 
                       > m_tags;

  CnC::item_collection< TaskTag<0, TASKTAGDIMMACRO, INTERTASKDIMMACRO>, 
                        void *, polyTask_tuner<0, TASKTAGDIMMACRO, INTERTASKDIMMACRO> >&
  getItemCollection(const TaskTag<0, TASKTAGDIMMACRO, INTERTASKDIMMACRO> &t) {
    return M;
  }  

  polyTask_context() : 
    m_tuner(), 
    M(*this, "M", m_tuner),  
    m_tags(*this), 
    m_steps(*this)
  {

    Threading::dumpThreadInfo(std::cerr, " polytask_init ");

    // prescription
    m_tags.prescribes( m_steps, *this );

    // producer/consumer
    m_steps.consumes( M );
    m_steps.produces( M );
  }

};


#endif



// #ifndef __POLYTASK_H__
// #define __POLYTASK_H__

// #include "tbb/combinable.h"
// #include "cnc/cnc.h"
// #include "cnc/default_tuner.h"

// using namespace std;

// #include "cnc/debug.h"

// // forward declaration
// template <int TASK_ID, int TASKTAGDIM, int INTERTASKDIM>
// class polyTask_context;

// #include "TaskTag.hpp"
// #include "Threading.hpp"

// // PolyTask core class
// template <int TASK_ID, int TASKTAGDIM, int INTERTASKDIM> class polyTask_step {
// public:
//   mutable tbb::combinable<bool> pinned;
//   polyTask_step() : pinned(false) {}

//   int64_t execute
//   (const TaskTag<TASK_ID, TASKTAGDIM, INTERTASKDIM> &, 
//    polyTask_context<TASK_ID, TASKTAGDIM, INTERTASKDIM> &) const;
// };

// // PolyTask tuner class
// template <int TASK_ID, int TASKTAGDIM, int INTERTASKDIM> class polyTask_tuner : 
//   public CnC::step_tuner<>, public CnC::tag_tuner<>, public CnC::hashmap_tuner {
// public:
//   polyTask_tuner() {}
//   template< class DC >
//   void depends(const TaskTag<TASK_ID, TASKTAGDIM, INTERTASKDIM> &, 
//                polyTask_context<TASK_ID, TASKTAGDIM, INTERTASKDIM> &, DC &) const;

//   int64_t compute_on(const TaskTag<TASK_ID, TASKTAGDIM, INTERTASKDIM> &, 
//                      polyTask_context<TASK_ID, TASKTAGDIM, INTERTASKDIM> &) const;
// };


// // Context for a single polyTask 
// template <int TASK_ID, int TASKTAGDIM, int INTERTASKDIM> class polyTask_context : 
// public CnC::context< polyTask_context<TASK_ID, TASKTAGDIM, INTERTASKDIM> > {
// public:
//   polyTask_tuner <TASK_ID, TASKTAGDIM, INTERTASKDIM> m_tuner;

//   CnC::item_collection< TaskTag<TASK_ID, TASKTAGDIM, INTERTASKDIM>, 
//                         void *, polyTask_tuner<TASK_ID, TASKTAGDIM, INTERTASKDIM> > M;

//   CnC::step_collection< polyTask_step<TASK_ID, TASKTAGDIM, INTERTASKDIM>, 
//                         polyTask_tuner<TASK_ID, TASKTAGDIM, INTERTASKDIM> 
//                         > m_steps;

//   CnC::tag_collection< TaskTag<TASK_ID, TASKTAGDIM, INTERTASKDIM> , 
//                        polyTask_tuner<TASK_ID, TASKTAGDIM, INTERTASKDIM> 
//                        > m_tags;

//   polyTask_context() : 
//     m_tuner(), 
//     M(*this, "M", m_tuner), 
//     m_tags(*this), m_steps(*this) {

//     Threading::dumpThreadInfo(std::cerr, " polytask_init ");

//     // prescription
//     m_tags.prescribes( m_steps, *this );

//     // producer/consumer
//     m_steps.consumes( M );
//     m_steps.produces( M );
//   }

// };


// #endif
